package com.im.service.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.im.codec.pack.user.UserModifyPack;
import com.im.common.ClientType;
import com.im.service.config.AppConfig;
import com.im.common.constant.Constants;
import com.im.common.enums.DelFlagEnum;
import com.im.common.enums.exception.UserErrorCode;
import com.im.common.enums.command.UserEventCommand;
import com.im.common.exception.BusinessException;
import com.im.common.route.RouteHandle;
import com.im.common.route.RouteInfo;
import com.im.common.utils.RouteInfoParseUtil;
import com.im.service.group.service.ImGroupService;
import com.im.service.user.entity.ImUserDataEntity;
import com.im.service.user.mapper.UserDataMapper;
import com.im.service.user.model.param.*;
import com.im.service.user.model.result.GetUserInfoResult;
import com.im.service.user.model.result.ImportUserResult;
import com.im.service.user.service.ImUserService;
import com.im.service.utils.CallbackService;
import com.im.service.utils.MessageProducer;
import com.im.service.utils.ZKit;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ImUserServiceImpl extends ServiceImpl<UserDataMapper, ImUserDataEntity> implements ImUserService {

    @Autowired
    private CallbackService callbackService;
    @Autowired
    private MessageProducer messageProducer;
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RouteHandle routeHandle;
    @Autowired
    private ZKit zKit;
    @Autowired
    private AppConfig appConfig;

    @Override
    public ImportUserResult importUser(ImportUserParam param) {
        if (param.getUserData().size() > 100) {
            throw new BusinessException(UserErrorCode.IMPORT_SIZE_BEYOND);
        }

        ImportUserResult result = new ImportUserResult();
        List<String> successId = new ArrayList<>();
        List<String> errorId = new ArrayList<>();

        for (ImUserDataEntity data : param.getUserData()) {
            try {
                data.setAppId(param.getAppId());
                boolean save = save(data);
                if (save) {
                    successId.add(data.getUserId());
                }
            } catch (Exception e) {
                e.printStackTrace();
                errorId.add(data.getUserId());
            }
        }

        result.setErrorId(errorId);
        result.setSuccessId(successId);
        return result;
    }

    @Override
    public ImportUserResult deleteUser(DeleteUserParam param) {
        ImUserDataEntity entity = new ImUserDataEntity();
        entity.setDelFlag(DelFlagEnum.DELETE.getCode());

        List<String> errorId = new ArrayList();
        List<String> successId = new ArrayList();

        for (String userId : param.getUserId()) {
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.eq("app_id", param.getAppId());
            wrapper.eq("user_id", userId);
            wrapper.eq("del_flag", DelFlagEnum.NORMAL.getCode());
            boolean update = false;
            try {
                update = update(entity, wrapper);
                if (update) {
                    successId.add(userId);
                } else {
                    errorId.add(userId);
                }
            } catch (Exception e) {
                errorId.add(userId);
            }
        }

        ImportUserResult result = new ImportUserResult();
        result.setSuccessId(successId);
        result.setErrorId(errorId);

        return result;
    }

    @Override
    public GetUserInfoResult getUserInfo(GetUserInfoParam param) {
        // 构造查询条件
        QueryWrapper<ImUserDataEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("app_id", param.getAppId());
        queryWrapper.in("user_id", param.getUserIds());
        queryWrapper.eq("del_flag", DelFlagEnum.NORMAL.getCode());

        // 执行查询操作
        List<ImUserDataEntity> userDataEntities = list(queryWrapper);

        // 将查询结果转换为 HashMap 方便后续操作
        HashMap<String, ImUserDataEntity> map = new HashMap<>();
        for (ImUserDataEntity data : userDataEntities) {
            map.put(data.getUserId(), data);
        }

        // 检查查询失败的用户 ID 列表
        List<String> failUser = new ArrayList<>();
        for (String uid : param.getUserIds()) {
            if (!map.containsKey(uid)) {
                failUser.add(uid);
            }
        }

        // 构造返回结果
        GetUserInfoResult result = new GetUserInfoResult();
        result.setUserDataItem(userDataEntities);
        result.setFailUser(failUser);
        return result;
    }

    @Override
    public ImUserDataEntity getSingleUserInfo(String userId, Integer appId) {
        QueryWrapper objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("app_id", appId);
        objectQueryWrapper.eq("user_id", userId);
        objectQueryWrapper.eq("del_flag", DelFlagEnum.NORMAL.getCode());
        ImUserDataEntity userData = getOne(objectQueryWrapper);
        if (userData == null) {
            throw new BusinessException(UserErrorCode.USER_IS_NOT_EXIST);
        }
        return userData;
    }

    @Override
    public void modifyUserInfo(ModifyUserInfoParam param) {
        // 构建查询条件
        QueryWrapper query = new QueryWrapper<>();
        query.eq("app_id", param.getAppId());
        query.eq("user_id", param.getUserId());
        query.eq("del_flag", DelFlagEnum.NORMAL.getCode());
        // 查询用户数据
        ImUserDataEntity user = getOne(query);
        // 如果用户不存在，则抛出业务异常
        if (user == null) {
            throw new BusinessException(UserErrorCode.USER_IS_NOT_EXIST);
        }

        // 构建更新数据对象
        ImUserDataEntity update = new ImUserDataEntity();
        BeanUtils.copyProperties(param, update);

        // 设置appId和userId为null，避免更新时被覆盖
        update.setAppId(null);
        update.setUserId(null);
        // 执行更新操作
        boolean updateFlag = update(update, query);
        // 如果更新成功，则发送用户修改事件和回调请求
        if (updateFlag) {
            // 构建用户修改事件对象
            UserModifyPack pack = new UserModifyPack();
            BeanUtils.copyProperties(param, pack);
            // 发送用户修改事件
            messageProducer.sendToUser(param.getUserId(), param.getClientType(), param.getImei(), UserEventCommand.USER_MODIFY, pack, param.getAppId());

            // 如果开启了修改用户信息后回调功能，则发送回调请求
            if (appConfig.isModifyUserAfterCallback()) {
                callbackService.callback(param.getAppId(), Constants.CallbackCommand.ModifyUserAfter, JSONObject.toJSONString(param));
            }
        } else {
            // 如果更新失败，则抛出业务异常
            throw new BusinessException(UserErrorCode.MODIFY_USER_ERROR);
        }
    }

    @Override
    public RouteInfo login(LoginParam param) {
        // 登录验证
        Boolean isOk = true;
        // 登录验证成功
        if (isOk) {
            // 获取所有可用的服务器节点
            List<String> allNode = null;
            // 判断客户端类型，获取相应类型的服务器节点
            if (param.getClientType() == ClientType.WEB.getCode()) {
                allNode = zKit.getAllWebNode();
            } else {
                allNode = zKit.getAllTcpNode();
            }
            // 根据用户ID进行服务器路由选择
            String address = routeHandle.routeServer(allNode, param.getUserId());
            // 解析服务器路由信息
            RouteInfo parse = RouteInfoParseUtil.parse(address);
            // 返回服务器路由信息
            return parse;
        } else {
            throw new BusinessException(500, "登录失败");
        }
    }

    @Override
    public Map getUserSequence(GetUserSequenceParam req) {
        Map<Object, Object> map = stringRedisTemplate.opsForHash().entries(req.getAppId() + ":" + Constants.RedisConstants.SeqPrefix + ":" + req.getUserId());
        Long groupSeq = imGroupService.getUserGroupMaxSeq(req.getUserId(), req.getAppId());
        map.put(Constants.SeqConstants.Group, groupSeq);
        return map;
    }
}
